package org.scboy.coobi.log;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import org.scboy.coobi.caches.GetSystemConfig;
import org.scboy.coobi.properties.CoobiProperties;
import org.scboy.utils.caches.dbms.entity.SystemConfigEntity;
import org.scboy.utils.entitys.coobi.DataAlterColumn;
import org.scboy.utils.entitys.coobi.DataAlterTable;
import org.scboy.utils.entitys.coobi.DbColumn;
import org.scboy.utils.entitys.coobi.DbTable;
import org.scboy.utils.entitys.coobi.Model;
import org.scboy.utils.entitys.rbac.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import jakarta.servlet.http.HttpServletRequest;

@Configuration
public class DataAlterLog {

	Log log=LogFactory.get();
	
	@Autowired
	CoobiProperties properties;
	
	@Autowired
	DataAlterService service;
	
	@Autowired
	GetSystemConfig config;

	/**
	 * 获取Token，用于记录数据变更线路。
	 * @return
	 */
	public Model getHeadValue() {
		LoginUser loginUser=null;
		
		String requestId="";
		try {
			RequestAttributes ra=RequestContextHolder.getRequestAttributes();
			if(!Objects.isNull(ra)) {
				ServletRequestAttributes sra=(ServletRequestAttributes)ra;
				HttpServletRequest request = sra.getRequest();
				
				Object login=request.getAttribute("LOGIN_USER");
				if(login!=null) {
					loginUser=(LoginUser)login;
				}
				requestId=(String)request.getHeader("Bmps-Request-Id");
			}
		} catch (Exception e) {
			log.warn("无法获取登用户TOKEN");
		}
		
		return Model.create().add("loginUser", loginUser).add("requestId", requestId);
	}
	
	/**
	 * 处理数据
	 * @param DbType
	 * @param value
	 * @return
	 */
	private String getValue(String DbType,Object value) {
		
		String [] dateType=new String[] {"DATE","TIME","DATETIME"};
		
		//如果是时间格式
		if(ArrayUtil.contains(dateType, DbType.toUpperCase(Locale.ENGLISH))) {
			if(value!=null) {
				Date date=Convert.toDate(value);
				if(date==null) {
					return "";
				}else {
					return DateUtil.format(date, "yyyy-MM-dd HH:mm:ss.SSS");
				}
			}else {
				return "";
			}
		}else {
			String val = Convert.toStr(value);
			if(StrUtil.isEmpty(val)) {
				return "";
			}else {
				return val;
			}
		}
	}
	
	/**
	 * 检查是否允许记录日志
	 * @param table
	 * @return
	 */
	public boolean checkAlter(String table) {
		
		SystemConfigEntity configEntity = config.getConfig("LOGGER_OPEN_DB_LOG");
		if(configEntity!=null) {
			if("CLOSE".equals(configEntity.getValue())) {
				return false;
			}
		}
		
		Object loginUser=getHeadValue().getString("loginUser");
		
		/**
		 * 是否记录数据变更日志，并且不是忽略的表
		 */
		if(loginUser!=null && properties.isOpenDataAlterLog() && !ArrayUtil.contains(properties.getIgnoreTable(), table)) {
			return true;
		}else {
			return false;
		}
	}
	
	/**
	 * 新增数据日志
	 * @param table 改变时的表
	 * @param nowData 改变时的新数据
	 * @param exeSql 改变时执行的SQL
	 * @param params 改变时执行SQL的参数
	 */
	public void insertAlter(DbTable table, Model nowData,String exeSql,Object [] params) {
		
		Model headValue=getHeadValue();
		
		LoginUser loginUser=(LoginUser)headValue.get("loginUser");
		
		DataAlterTable alertTable= new DataAlterTable();
		alertTable.setToken(loginUser.getToken());
		alertTable.setUserId(loginUser.getUserInfo().getId());
		alertTable.setUserName(loginUser.getUserInfo().getUserName());
		alertTable.setOrgId(loginUser.getUserInfo().getOrg().getId());
		alertTable.setRequestId(headValue.getString("requestId"));
		alertTable.setTableName(table.getName());
		alertTable.setComment(table.getComment());
		alertTable.setExeSql(exeSql);
		alertTable.setParams(params);
		
		List<DataAlterColumn> alertColumns=new ArrayList<DataAlterColumn>();

		List<DataAlterColumn> primary=new ArrayList<DataAlterColumn>();
		
		for (DbColumn column : table.getColumns()) {
			if(nowData.containsKey(column.getEntityName())) {
				
				String value=getValue(column.getDbType(),nowData.get(column.getEntityName()));
				DataAlterColumn alterColumn=new DataAlterColumn();
				alterColumn.setColumnName(column.getName());
				alterColumn.setComment(column.getComment());
				alterColumn.setEntityName(column.getEntityName());
				alterColumn.setNewValue(value);
				alterColumn.setOldValue("");
				alterColumn.setPrimaryValue(value);
				alertColumns.add(alterColumn);
				
				if(column.isPrimary()) {
					primary.add(alterColumn);
				}
			}
		}

		if(alertColumns.size()>0) {
			alertTable.setColumns(alertColumns);
			alertTable.setPrimary(primary);
			//同步执行日志记录服务
			service.dataAlert("INSERT", alertTable);
		}
	}
	
	/**
	 * 修改数据日志
	 * @param table 改变时的表
	 * @param nowData 改变时新数据
	 * @param oldDatas 改变时旧数据
	 * @param exeSql 改变时执行的SQL
	 * @param params 改变时执行SQL的参数
	 */
	public void updateAlter(DbTable table,Model nowData,List<Model> oldDatas,String exeSql,Object [] params) {

		Model headValue=getHeadValue();

		LoginUser loginUser=(LoginUser)headValue.get("loginUser");
		
		for (Model oldData : oldDatas) {
			DataAlterTable alertTable= new DataAlterTable();
			alertTable.setToken(loginUser.getToken());
			alertTable.setUserId(loginUser.getUserInfo().getId());
			alertTable.setUserName(loginUser.getUserInfo().getUserName());
			alertTable.setOrgId(loginUser.getUserInfo().getOrg().getId());
			alertTable.setRequestId(headValue.getString("requestId"));
			alertTable.setTableName(table.getName());
			alertTable.setComment(table.getComment());
			alertTable.setExeSql(exeSql);
			alertTable.setParams(params);
			
			List<DataAlterColumn> alertColumns=new ArrayList<DataAlterColumn>();
			
			List<DataAlterColumn> primary=new ArrayList<DataAlterColumn>();
			
			for (DbColumn column : table.getColumns()) {

				String oldValue=getValue(column.getDbType(),oldData.getString(column.getEntityName()));
				
				if(column.isPrimary()) {
					DataAlterColumn alterColumn=new DataAlterColumn();
					alterColumn.setColumnName(column.getName());
					alterColumn.setComment(column.getComment());
					alterColumn.setEntityName(column.getEntityName());
					alterColumn.setPrimaryValue(oldValue);
					primary.add(alterColumn);
				}
				
				//如果不是更新数据，跳过
				if(!nowData.containsKey(column.getEntityName())) {
					continue;
				}
				
				String newValue=getValue(column.getDbType(),nowData.getString(column.getEntityName()));
				
				if(!newValue.equals(oldValue)) {
					DataAlterColumn alterColumn=new DataAlterColumn();
					alterColumn.setColumnName(column.getName());
					alterColumn.setComment(column.getComment());
					alterColumn.setEntityName(column.getEntityName());
					alterColumn.setNewValue(newValue);
					alterColumn.setOldValue(oldValue);
					alertColumns.add(alterColumn);
				}
			}

			if(alertColumns.size()>0) {
				alertTable.setColumns(alertColumns);
				alertTable.setPrimary(primary);
				//同步执行日志记录服务
				service.dataAlert("UPDATE", alertTable);
			}
		}
	}
	
	/**
	 * 删除数据日志
	 * @param table 改变时的表
	 * @param oldDatas 改变时的数据
	 * @param exeSql 改变是执行的SQL
	 * @param params 改变时执行SQL的参数
	 */
	public void deleteAlter(DbTable table,List<Model> oldDatas,String exeSql,Object [] params) {

		Model headValue=getHeadValue();

		LoginUser loginUser=(LoginUser)headValue.get("loginUser");
		
		for (Model oldData : oldDatas) {
			DataAlterTable alertTable= new DataAlterTable();
			alertTable.setToken(loginUser.getToken());
			alertTable.setUserId(loginUser.getUserInfo().getId());
			alertTable.setUserName(loginUser.getUserInfo().getUserName());
			alertTable.setOrgId(loginUser.getUserInfo().getOrg().getId());
			alertTable.setRequestId(headValue.getString("requestId"));
			alertTable.setTableName(table.getName());
			alertTable.setComment(table.getComment());
			alertTable.setExeSql(exeSql);
			alertTable.setParams(params);
			
			List<DataAlterColumn> alertColumns=new ArrayList<DataAlterColumn>();
			
			List<DataAlterColumn> primary=new ArrayList<DataAlterColumn>();
			
			for (DbColumn column : table.getColumns()) {
				String oldValue=getValue(column.getDbType(),oldData.getString(column.getEntityName()));
				
				DataAlterColumn alterColumn=new DataAlterColumn();
				alterColumn.setColumnName(column.getName());
				alterColumn.setComment(column.getComment());
				alterColumn.setEntityName(column.getEntityName());
				alterColumn.setNewValue("");
				alterColumn.setOldValue(oldValue);
				alterColumn.setPrimaryValue(oldValue);
				alertColumns.add(alterColumn);
				
				if(column.isPrimary()) {
					primary.add(alterColumn);
				}
			}
			
			if(alertColumns.size()>0) {
				alertTable.setColumns(alertColumns);
				alertTable.setPrimary(primary);
				//同步执行日志记录服务
				service.dataAlert("DELETE", alertTable);
			}
		}
	}
}
